package com.lc;

import com.lc.config.Configuration;
import com.lc.constants.HttpConstants;
import com.lc.mode.Request;
import com.lc.mode.Response;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;

/**
 * @author liuc
 * @date 2021/5/5
 * @description 处理连接的线程(主)
 **/
public class Master extends Thread {

    // 多路复用选择器
    private Selector selector;
    private Configuration configuration;

    public Master(Configuration configuration) {
        this.configuration = configuration;
        try {
            // 1.打开多路复用选择器
            this.selector = Selector.open();
            // 2.打开服务器通道
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            // 3.设置非阻塞
            serverSocketChannel.configureBlocking(false);
            // 4.绑定地址
            serverSocketChannel.bind(new InetSocketAddress(this.configuration.getPort()));
            // 5.注册上去
            serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);
            System.out.println("server start success...");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            while (true) {
                //给一个打断的机会
                if (Thread.interrupted()) {
                    System.out.println("thread is interrupted! stop mini-cat!!!");
                    break;
                }
                // 1.必须让 selector 开始监听, 100毫秒的间隔
                this.selector.select(100);
                // 2.获取多路选择器所有的结果集
                Iterator<SelectionKey> keyIterator = this.selector.selectedKeys().iterator();
                // 3.循环key
                while (keyIterator.hasNext()) {
                    // 4.获取一个选择的元素
                    SelectionKey selectionKey = keyIterator.next();
                    // 5.删除这个元素
                    keyIterator.remove();
                    // 6.判断是否可用
                    if (selectionKey.isValid()) {
                        // 阻塞的时候
                        if (selectionKey.isAcceptable()) {
                            accept(selectionKey);
                        }
                        // 读取的时候
                        if (selectionKey.isReadable()) {
                            doRead(selectionKey);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //接受连接，注册事件
    public void accept(SelectionKey key) throws IOException {
        ServerSocketChannel server = (ServerSocketChannel) key.channel();
        //拿到请求连接
        SocketChannel accept = server.accept();
        if (accept != null) {
            System.out.println("accept: " + accept.getRemoteAddress());
            //设置请求连接非阻塞
            accept.configureBlocking(false);
            //将此次请求连接注册, 后续在读事件完了后需要关闭
            accept.register(selector, SelectionKey.OP_READ);
        }
    }

    public void doRead(SelectionKey key) throws IOException {
        //todo 考虑让线程池去做，但是会报异常????
        SocketChannel channel = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        if(channel.read(buffer) < 0){ //保证读到数据
            channel.close();
            return;
        }
        buffer.flip();
        byte[] content = new byte[buffer.limit()];
        //读到字节数组中
        buffer.get(content);
        Request request = new Request(content);
        buffer.clear();
        Response response = new Response(channel);
        //交给httpHandler去处理
        this.configuration.getProtocolHandler().handle(request,response);
        channel.close();
    }
}
